import RouterLink from "./components/RouterLink";
import RouterView from "./components/RouterView";
import { createMatcher } from "./create-matcher";
import HashHistroy from "./history/hash";
import BrowserHistory from "./history/history";

export let Vue;

class VueRouter {
  constructor(options = {}) {
    this.matcher = createMatcher(options.routes || []);
    if (options.mode === "hash") {
      this.history = new HashHistroy(this);
    } else {
      this.history = new BrowserHistory(this);
    }
  }

  init(app) {
    const history = this.history;

    history.listen((route) => { // _route 就是我们定义的响应式数据
      app._route = route; // 每次跳转都重执行, 才会渲染页面, 否则路由变化了不会渲染页面
    })
    
    const setupListenerHandler = () => {
      history.setupListener(); // 监听 hash 值的变化 
    }

    history.transitionTo(history.getCurrentLocation(), setupListenerHandler)
  }

  match(location) {
    return this.matcher.match(location);
  }

  push(location) {
    // 跳转到这个路径
    this.history.transitionTo(location, () => {
      this.history.updateLocation(location);
    });
  }
}

VueRouter.install = (_Vue) => {
  Vue = _Vue;
  Vue.component("router-link", RouterLink);
  Vue.component("router-view", RouterView);

  Vue.mixin({
    beforeCreate() {
      // 在根组件中注入的 router, 共享给每个组件
      if (this.$options.router) {
        // console.log('root', this.$options.name)
        // 根组件
        this._routerRoot = this; // 将自己暴露出来
        this._router = this.$options.router; // 在自己的身上添加一个 _router 属性

        this._router.init(this);

        // 定义路由的响应式数据, 把 Base 中 的 current 设置为响应式的
        Vue.util.defineReactive(this, '_route', this._router.history.current);
        console.log(this._router.history.current, this._route)
      } else {
        // console.log('child', this.$options.name)
        // 子组件
        this._routerRoot = this.$parent && this.$parent._routerRoot;
        //以后子组件可以通过 this._routerRoot._router
      }
    }
  });

  Object.defineProperty(Vue.prototype, '$route', { // 用于方便组件的取值 {path:'/',matched:[],params,query}
    get() {
      return this._routerRoot._route;
    }
  })
  // router 的实例
  Object.defineProperty(Vue.prototype, '$router', { // 代理就是取值的时候才调用get方法  vm._data.xxx => vm.xxx
    get() {
      return this._routerRoot._router; // 有这些方法哦: match  push replace
    }
  })
};

export default VueRouter;
